using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Xml;

using IronPython.Hosting;
using IronPython.Compiler;
using System.IO;

namespace Athena
{
    public partial class ScriptControl : UserControl
    {

        private PythonEngine _Engine  = null;
        public PythonEngine Engine
        {
            get { return _Engine; }
            set { _Engine = value; }
        }

        private Stream _Stream;
        public Stream Stream
        {
            get { return _Stream; }
            set { _Stream = value; }
        }

        public ScriptControl()
        {
            InitializeComponent();
            txtScript.Text = "Script Console" + Environment.NewLine + "==============" + Environment.NewLine + Environment.NewLine + ">>";
            txtScript.Font = new Font(FontFamily.GenericMonospace, 10f);
            //GoToHomePosition();
            txtScript.OnCommandExecution += new Athena.Tools.CommandTextBox.OnCommandExecutionDelegate(txtScript_CommandInvoked);            
        }

        private void toolStripChangeFont_Click(object sender, EventArgs e)
        {
            FontDialog oDialog = new FontDialog();
            oDialog.Font = txtScript.Font;
            if (oDialog.ShowDialog() == DialogResult.OK)
            {
                txtScript.Font = oDialog.Font;
            }
        }

        private void pasteToolStripButton_Click(object sender, EventArgs e)
        {
            try
            {
                txtScript.Paste();
            }
            catch (Exception )
            {
            }
        }

        private void copyToolStripButton_Click(object sender, EventArgs e)
        {
            try
            {
                txtScript.Copy();
            }
            catch (Exception )
            {
            }
        }

        private void cutToolStripButton_Click(object sender, EventArgs e)
        {
            try
            {
                txtScript.Paste();                
            }
            catch (Exception )
            {
            }
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {

        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                ExecuteFile(openFileDialog1.FileName);
            }
        }

        /// <summary>
        /// Prevent some nasty keys ...
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="keyData"></param>
        /// <returns></returns>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (!Focused) return false;

            switch (keyData)
            {
                case Keys.Up:
                case Keys.Down:
                case Keys.Back:
                case Keys.Tab:
                case Keys.Enter:
                case Keys.Home:
                case Keys.Home & Keys.Shift:
                    return true;         
           
                default:
                    return base.ProcessCmdKey(ref msg, keyData);
            }
        }
        /*
        private void txtScript_KeyUp(object sender, KeyEventArgs e)
        {
            txtScript.SuspendLayout();
            try
            {
                switch (e.KeyCode)
                {
                    case Keys.Back:
                        try
                        {
                            int nStart = txtScript.SelectionStart;
                            
                            int nLastLine = txtScript.Text.LastIndexOf("\n", nStart);
                            if (nStart - nLastLine > 5)
                            {
                                txtScript.Text = txtScript.Text.Remove(nStart - 1, 1);
                                txtScript.SelectionStart = nStart - 1;
                            }
                        }
                        catch (Exception)
                        {
                        }
                        
                        
                        break;
                    case Keys.Delete:
                        break;
                    case Keys.Down:
                        GetNextCommand();
                        break;
                    case Keys.End:
                        break;
                    case Keys.Enter:
                        if (ModifierKeys != Keys.Shift)
                            TestLastLine();
                        else
                            txtScript.Text += Environment.NewLine;
                        e.Handled = true;
                        break;
                    case Keys.Escape:
                        ClearLine();
                        break;
                    case Keys.Home:
                        GoToHomePosition();
                        break;
                    case Keys.Up:
                        GetLastCommand();
                        break;                    
                    default:
                        e.Handled = false;
                        break;
                }
            }
            finally
            {
                txtScript.ResumeLayout();    
            }
        }


        private void GoToHomePosition()
        {
            string sText = txtScript.Text;
            //int nPos = txtScript.Find(">>> ", RichTextBoxFinds.Reverse);
            int nPos = sText.LastIndexOf(">>> ");
            txtScript.SelectionStart = nPos + 4;
            txtScript.SelectionLength = 0;
            txtScript.ScrollToCaret();
        }
        
        private void ClearLine()
        {
            int nStart = txtScript.SelectionStart;
            string sText = txtScript.Text;
            //int nPos = txtScript.Find(">>> ", RichTextBoxFinds.Reverse);
            int nPos = sText.LastIndexOf(">>> ", nStart);
            int nLength = nStart - nPos - 4;
            if (nLength > 0)
            txtScript.Text = txtScript.Text.Remove(nPos + 4, nLength);
            else
            txtScript.Text = txtScript.Text.Substring(0,nPos + 4);
            GoToHomePosition();
        }

        private void GetNextCommand()
        {
            if (_History.Count == 0) return;
            ClearLine();
            try
            {
                int nStart = txtScript.SelectionStart;
                nCurrentPos += 1;
                if (nCurrentPos > _History.Count - 1) { nCurrentPos = 0; return; }
                string entry = _History[nCurrentPos];
                txtScript.Text = txtScript.Text.Insert(txtScript.SelectionStart, entry);
                txtScript.SelectionStart = nStart + entry.Length;
                txtScript.ScrollToCaret();
            }
            catch (ArgumentOutOfRangeException)
            {
                nCurrentPos = _History.Count -1;
            }
            catch (Exception)
            {

            }

        }

        private void GetLastCommand()
        {
            if (_History.Count == 0) return;
            ClearLine();
            try
            {
                int nStart = txtScript.SelectionStart;
                nCurrentPos -= 1;
                if (nCurrentPos < 0) { nCurrentPos = _History.Count; return; }
                string entry = _History[nCurrentPos];
                txtScript.Text = txtScript.Text.Insert(txtScript.SelectionStart, entry);
                txtScript.SelectionStart = nStart + entry.Length;
                txtScript.ScrollToCaret();
            }
            catch (ArgumentOutOfRangeException)
            {
                nCurrentPos = 0;
            }
            catch (Exception)
            {

            }
        }
        */

        void txtScript_CommandInvoked(string text, EventArgs e)
        {
            ExecuteCommand(text);
        }

        private void ExecuteFile(string sFileName)
        {
            if (_Engine != null)
            {
                try
                {

                    StreamReader oReader = new StreamReader(sFileName);
                    string sScript = oReader.ReadToEnd();
                    sScript = sScript.Replace("\r\n", "\n");
                    oReader.Close();

                    //string[] sLines = sScript.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    //for (int i = 0; i < sLines.Length; i++)
                    //{
                    //    ExecuteCommand(sLines[i]);
                    //}



                    long nCurrent = _Stream.Position;                    
                    //ExecuteCommand(sScript);         
                    _Engine.Execute(sScript);
           
                    _Stream.Position = nCurrent;
                    StreamReader oTemp = new StreamReader(_Stream);
                    string sText = oTemp.ReadToEnd();
                    if (sText == "")
                    {
                        txtScript.Text += Environment.NewLine;
                    }
                    else
                    {
                        txtScript.Text += Environment.NewLine + Environment.NewLine + sText + Environment.NewLine;
                    }

                    
                }
                catch (IronPython.Runtime.Exceptions.PythonSyntaxErrorException ex)
                {
                    txtScript.Text += Environment.NewLine + "--> " + "Line: " + ex.Line + " Column: " + ex.Column +  " Error: " + ex.Message + Environment.NewLine;
                }
                catch (Exception ex)
                {                    
                    txtScript.Text += Environment.NewLine + "--> " + "Error: " + ex.Message + Environment.NewLine;
                }
                //GoToHomePosition();
            }
        }

        private void ExecuteCommand(string sCommand)
        {           
            if (_Engine != null)
            {
                try
                {
                    long nCurrent = _Stream.Position;   
                    _Engine.ExecuteToConsole(sCommand);
                    _Stream.Position = nCurrent;
                    StreamReader oTemp = new StreamReader(_Stream);
                    string sText = oTemp.ReadToEnd();
                    txtScript.Text += Environment.NewLine + "    " + sText + Environment.NewLine;
                    
                    /*_History.Add(sCommand);
                    nCurrentPos++;*/
                }
                catch (Exception ex)
                {
                    txtScript.Text += Environment.NewLine + "--> " + "Error: " + ex.Message + Environment.NewLine;
                    
                }
            }


        }
        /*private void TestLastLine()
        {
            string sLine = GetLastLine();
            if (sLine != "")
            ExecuteCommand(sLine);
            GoToHomePosition();
            txtScript.ScrollToCaret();
        }

        private string GetLastLine()
        {
            int nStart = txtScript.SelectionStart;
            string sText = txtScript.Text;
            int nPos = sText.LastIndexOf(">>> ", nStart);
            
            //int nPos = txtScript.Find(">>> ", nStart, RichTextBoxFinds.Reverse);
            
            if (nPos < 0) return "";

            nPos += 4;

            // find end of current line: 
            int nEnd = sText.IndexOf("\n", nStart - 1);   //txtScript.Text.IndexOf("\n", nStart);
            if (nEnd == -1) nEnd = sText.Length;
            string sLine = sText.Substring(nPos, nEnd - nPos);
            return sLine;

            //int nLength = nStart - nPos - 5;
            //if (nLength < 1)
            //    nLength = txtScript.Text.IndexOf("\n", nPos + 4) - nPos + 4;
            //if (nPos + 4 + nLength >= txtScript.Text.Length || nLength < 1)
            //    return "";
            //return txtScript.Text.Substring(nPos + 4, nLength);
        }
        
        List<string> _History = new List<string>();
        int nCurrentPos = -1;
        */
        /***********Human Readable MDL****************/

        private void simButton_Click(object sender, EventArgs e)
        {
            try
            {
                string filename = "model.txt";
                WriteFile(filename,modularScriptText.Text);
                StreamReader iStream = new StreamReader(new FileStream(filename, FileMode.Open));
                List<Core.Item> items = IO.ModuleReaderWriter.ReadModule(iStream,Program.Model.BackEndModel);
                iStream.Close();

                Core.Module module = items[0] as Core.Module;

                ToolManager.Instance.Simulator.CurrentModule = (module);
            }
            catch (Exception) { }
        }

        private void genButton_Click(object sender, EventArgs e)
        {
            try
            {
                WriteFile("model.txt", modularScriptText.Text);
                StreamReader reader = new StreamReader(new FileStream("model.txt", FileMode.Open));
                List<Athena.Core.Item> items = Athena.IO.ModuleReaderWriter.ReadModule(reader, Program.Model.BackEndModel);

                HistoryManager.History.SetControllPoint("Module added from Script window");
                foreach (Athena.Core.Item i in items)
                {
                    if (i.Drawable == null)
                        i.GenerateDrawable(new PointF(100, 100));
                    Program.Model.AddToModel(i.Drawable,false,false,false,false);
                }
                reader.Close();
                Utility.Refresh();
                Program.Model.OnModelChanged(EventArgs.Empty);
            }
            catch (Exception) { }
        }

        private void onLeaving(object sender, EventArgs e)
        {
            try
            {
                //ToolManager.Instance.Simulator.CurrentModule = null;
            }
            catch (Exception) { }
        }

        void WriteFile(string filename, string text)
        {
            StreamWriter oStream = new StreamWriter(new FileStream(filename, FileMode.Create));
            oStream.Write(text);
            oStream.Close();
            oStream.Dispose();
        }

        private void getCodeButton_Click(object sender, EventArgs e)
        {
            if (Program.Model.Selected.Count == 1 && Program.Model.Selected[0].Item is Core.Module)
                modularScriptText.Text = ((Core.Module)Program.Model.Selected[0].Item).ModularScript;
            else
                modularScriptText.Text = Program.Model.BackEndModel.ModularScript;
        }
    }
}
